package com.the_ring.chapter11.widget;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

import androidx.annotation.Nullable;

/**
 * 仿美图秀秀抠图自定义 View
 * 主要功能：
 * 1. 挪动高亮区域的手势：点击高亮区域内部，再滑动手势，即可将该区域拖拽至指定位置
 * 2. 调整高亮区域边界的手势：点击高亮区域边界，再滑动手势，即可将边界拖至指定位置
 * 3. 挪动图片的手势；点击高亮区域的的外部（阴影部分），然后滑动手势，即可将整张图片拖拽至指定位置
 * 4. 缩放图片的手势：两只手指同时按压屏幕，然后一起往中心点靠拢或彼此远离中心点，即可实现图片的缩小和方法操作
 * 5. 旋转图片的手势：两个手指同时按压屏幕，然后围绕中心点一起顺时针或逆时针旋转，即可实现图片的旋转操作
 *
 * @author the_ring
 * @date 2024-10-28
 */
public class ImageMattingView extends View {

    private static final String TAG = "ImageMattingView";

    private float widthSize;    // 布局宽度
    private float heightSize;   // 布局高度

    private Bitmap bitmap;      // 要修的位图
    private float bitmapWidth;  // 位图的原始宽度
    private float bitmapHeight; // 位图的原始高度

    private Paint bitmapPaint;  // 图片画笔
    private Paint shadowPaint;  // 阴影画笔
    private Paint linePaint;   // 高亮区域画笔


    private boolean initTag;    // 是否首次绘制
    private int lineLeft;       // 选择框的范围
    private int lineTop;
    private int lineRight;
    private int lineBottom;

    // 点击区域标志
    private int touchTag;
    private final int TOP_LEFT_CORNER = 0;
    private final int UPPER_EDGE = 1;
    private final int TOP_RIGHT_CORNER = 2;
    private final int RIGHT_EDGE = 3;
    private final int BOTTOM_RIGHT_CORNER = 4;
    private final int BOTTOM_EDGE = 5;
    private final int BOTTOM_LEFT_CORNER = 6;
    private final int LEFT_EDGE = 7;
    private final int PICTURE = 8;
    private final int SHADOW = 9;
    private final int ZOOM = 10;
    private final int NONE = 11;


    private Rect srcRect;
    private Rect dstRect;


    public ImageMattingView(Context context) {
        this(context, null);
    }

    public ImageMattingView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ImageMattingView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, defStyleAttr, 0);
    }

    public ImageMattingView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        widthSize = MeasureSpec.getSize(widthMeasureSpec);
        heightSize = MeasureSpec.getSize(heightMeasureSpec);

        bitmapPaint = new Paint();
        bitmapPaint.setStrokeWidth(0);

        shadowPaint = new Paint();
        shadowPaint.setColor(Color.parseColor("#a3000000"));
        // shadowPaint.setStrokeWidth(4);
        shadowPaint.setStyle(Paint.Style.FILL);

        linePaint = new Paint();
        linePaint.setColor(Color.parseColor("#ffffff"));
        // linePaint.setStrokeWidth(20);
        linePaint.setShadowLayer(0, 0, 0, 0);
        linePaint.setStyle(Paint.Style.FILL_AND_STROKE);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (bitmap == null) return;

        if (initTag) {
            lineLeft = 50;
            lineTop = 50;
            lineRight = (int) widthSize - 50;
            lineBottom = (int) heightSize - 50;
            initTag = false;


            /**
             * 绘制图片
             */
            // canvas.drawBitmap(bitmap, 0, 0, bitmapPaint); // 此方法不会对图片做任何处理，从指定位置显示，超出屏幕区域不显示
            // Bitmap裁剪区域
            srcRect = new Rect(0, 0, (int) bitmapWidth, (int) bitmapHeight);
            // 计算比例保障图片不变形
            float widthScale = (widthSize - 100) / bitmapWidth;  // 流出空余空间便于裁剪框的控制
            float heightScale = (heightSize - 100) / bitmapHeight;
            Log.i(TAG, "widthSize: " + widthSize + ", heightSize: " + heightSize);
            Log.i(TAG, "bitmapWidth: " + bitmapWidth + ", bitmapHeight: " + bitmapHeight);
            Log.i(TAG, "widthScale: " + widthScale + ", heightScale: " + heightScale);
            if (widthScale < heightScale) {
                float srcBitmapHeight = bitmapHeight * widthScale;
                lineTop = (int) (heightSize / 2 - srcBitmapHeight / 2);
                lineBottom = (int) (lineTop + srcBitmapHeight);
            } else {
                float srcBitmapWidth = bitmapWidth * heightScale;
                lineLeft = (int) (widthSize / 2 - srcBitmapWidth / 2) - 1;
                lineRight = (int) (lineLeft + srcBitmapWidth);
            }
            Log.i(TAG, "left: " + lineLeft + ", top: " + lineTop + ", right: " + lineRight + " , bottom: " + lineBottom);
            // 图片显示区域
            dstRect = new Rect(lineLeft, lineTop, lineRight, lineBottom);
        }
        canvas.drawBitmap(bitmap, srcRect, dstRect, bitmapPaint);

        /**
         * 绘制选中框
         */
        canvas.drawLine(lineLeft, lineTop, lineRight, lineTop, linePaint);
        canvas.drawLine(lineRight, lineTop, lineRight, lineBottom, linePaint);
        canvas.drawLine(lineLeft, lineBottom, lineRight, lineBottom, linePaint);
        canvas.drawLine(lineLeft, lineTop, lineLeft, lineBottom, linePaint);

        /**
         * 绘制阴影区域
         */
        canvas.drawRect(0, 0, widthSize, lineTop, shadowPaint);
        canvas.drawRect(0, lineTop, lineLeft, lineBottom, shadowPaint);
        canvas.drawRect(lineRight, lineTop, widthSize, lineBottom, shadowPaint);
        canvas.drawRect(0, lineBottom, widthSize, heightSize, shadowPaint);
    }

    private float lastX, lastY;

    private float fistLastX, fistLastY, secondLastX, secondLastY;
    private float centerX, centerY; // 缩放的中心点
    private float lastDistance;
    private RectF originRect;   // 缩放时保存原始位置

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float x = event.getX();
        float y = event.getY();
        switch (event.getAction() & MotionEvent.ACTION_MASK) {
            // 选择框边缘 50 区域都是区域选择
            case MotionEvent.ACTION_DOWN:
                if (x < lineLeft - 25) {
                    Log.i(TAG, "点击图片左侧阴影区域");
                    touchTag = SHADOW;
                } else if (x >= lineLeft - 25 && x <= lineLeft + 25) {
                    if (y < lineTop - 25) {
                        Log.i(TAG, "点击图片上侧阴影区域");
                        touchTag = SHADOW;
                    } else if (y >= lineTop - 25 && y <= lineTop + 25) {
                        Log.i(TAG, "点击选择框左上角");
                        touchTag = TOP_LEFT_CORNER;
                    } else if (y > lineTop + 25 && y < lineBottom - 25) {
                        Log.i(TAG, "点击选择框左边缘");
                        touchTag = LEFT_EDGE;
                    } else if (y >= lineBottom - 25 && y <= lineBottom + 25) {
                        Log.i(TAG, "点击选择框左下角");
                        touchTag = BOTTOM_LEFT_CORNER;
                    } else if (y > lineBottom + 25) {
                        Log.i(TAG, "点击图片下侧阴影区域");
                        touchTag = SHADOW;
                    }
                } else if (x > lineLeft + 25 && x < lineRight - 25) {
                    if (y < lineTop - 25) {
                        Log.i(TAG, "点击图片上侧阴影区域");
                        touchTag = SHADOW;
                    } else if (y >= lineTop - 25 && y <= lineTop + 25) {
                        Log.i(TAG, "点击选择框上边缘");
                        touchTag = UPPER_EDGE;
                    } else if (y > lineTop + 25 && y < lineBottom - 25) {
                        Log.i(TAG, "点击图片区域");
                        touchTag = PICTURE;
                    } else if (y >= lineBottom - 25 && y <= lineBottom + 25) {
                        Log.i(TAG, "点击选择框下边缘");
                        touchTag = BOTTOM_EDGE;
                    } else if (y > lineBottom + 25) {
                        Log.i(TAG, "点击图片下侧阴影区域");
                        touchTag = SHADOW;
                    }
                } else if (x >= lineRight - 25 && x <= lineRight + 25) {
                    if (y < lineTop - 25) {
                        Log.i(TAG, "点击图片上侧阴影区域");
                        touchTag = SHADOW;
                    } else if (y >= lineTop - 25 && y <= lineTop + 25) {
                        Log.i(TAG, "点击选择框右上角");
                        touchTag = TOP_RIGHT_CORNER;
                    } else if (y > lineTop + 25 && y < lineBottom - 25) {
                        Log.i(TAG, "点击选择框右边缘");
                        touchTag = RIGHT_EDGE;
                    } else if (y >= lineBottom - 25 && y <= lineBottom + 25) {
                        Log.i(TAG, "点击选择框右下角");
                        touchTag = BOTTOM_RIGHT_CORNER;
                    } else if (y > lineBottom + 25) {
                        Log.i(TAG, "点击图片下侧阴影区域");
                        touchTag = SHADOW;
                    }
                } else if (x > lineRight + 25) {
                    Log.i(TAG, "点击图片右侧阴影区域");
                    touchTag = SHADOW;
                }
                break;
            case MotionEvent.ACTION_POINTER_DOWN:
                originRect = new RectF(dstRect.left, dstRect.top, dstRect.right, dstRect.bottom);
                fistLastX = event.getX(0);
                fistLastY = event.getY(0);
                secondLastX = event.getX(1);
                secondLastY = event.getY(1);

                lastDistance = (float) Math.sqrt((secondLastX - fistLastX) * (secondLastX - fistLastX) + (secondLastY - fistLastY) * (secondLastY - fistLastY));

                centerX = (fistLastX + secondLastX) / 2;
                centerY = (fistLastY + secondLastY) / 2;
                if (originRect.contains(centerX, centerY)) {
                    touchTag = ZOOM;
                } else {
                    touchTag = NONE;
                }
                break;
            case MotionEvent.ACTION_MOVE:
                if (touchTag == TOP_LEFT_CORNER) {
                    lightLeftMove(x, y);
                    lightTopMove(x, y);
                } else if (touchTag == UPPER_EDGE) {
                    lightTopMove(x, y);
                } else if (touchTag == TOP_RIGHT_CORNER) {
                    lightTopMove(x, y);
                    lightRightMove(x, y);
                } else if (touchTag == RIGHT_EDGE) {
                    lightRightMove(x, y);
                } else if (touchTag == BOTTOM_RIGHT_CORNER) {
                    lightRightMove(x, y);
                    lightBottomMove(x, y);
                } else if (touchTag == BOTTOM_EDGE) {
                    lightBottomMove(x, y);
                } else if (touchTag == BOTTOM_LEFT_CORNER) {
                    lightBottomMove(x, y);
                    lightLeftMove(x, y);
                } else if (touchTag == LEFT_EDGE) {
                    lightLeftMove(x, y);
                } else if (touchTag == PICTURE) {
                    // 拖动高亮区域边框随着调整
                    int distanceX = (int) (x - lastX);
                    int distanceY = (int) (y - lastY);
                    lightLeftMove(lineLeft + distanceX, y);
                    lightRightMove(lineRight + distanceX, y);
                    lightTopMove(x, lineTop + distanceY);
                    lightBottomMove(x, lineBottom + distanceY);
                } else if (touchTag == SHADOW) {
                    // 移动图片
                    int distanceX = (int) (x - lastX);
                    int distanceY = (int) (y - lastY);
                    if (dstRect.left + distanceX < lineRight - 50 && dstRect.right + distanceX > lineLeft + 50) {
                        dstRect.left = dstRect.left + distanceX;
                        dstRect.right = dstRect.right + distanceX;
                    }
                    if (dstRect.top + distanceY < lineBottom - 50 && dstRect.bottom + distanceY > lineTop + 50) {
                        dstRect.top = dstRect.top + distanceY;
                        dstRect.bottom = dstRect.bottom + distanceY;
                    }

                    if (dstRect.left > lineLeft) {
                        lineLeft = dstRect.left;
                    }
                    if (dstRect.top > lineTop) {
                        lineTop = dstRect.top;
                    }
                    if (dstRect.right < lineRight) {
                        lineRight = dstRect.right;
                    }
                    if (dstRect.bottom < lineBottom) {
                        lineBottom = dstRect.bottom;
                    }
                } else if (touchTag == ZOOM) {
                    if (event.getPointerCount() >= 2) {
                        float x_1 = event.getX(1);
                        float y_1 = event.getY(1);

                        float distance = (float) Math.sqrt((x_1 - x) * (x_1 - x) + (y_1 - y) * (y_1 - y));
                        float scale = distance / lastDistance;
                        int left = (int) (centerX - (centerX - originRect.left) * scale);
                        int top = (int) (centerY - (centerY - originRect.top) * scale);
                        int right = (int) (centerX + (originRect.right - centerX) * scale);
                        int bottom = (int) (centerY + (originRect.bottom - centerY) * scale);

                        if (right - left < 200 || bottom - top < 200) {
                            break;  // 不能缩放到太小
                        }
                        dstRect.left = left;
                        dstRect.top = top;
                        dstRect.right = right;
                        dstRect.bottom = bottom;

                        lineLeft = left > lineLeft ? left : lineLeft;
                        lineTop = top > lineTop ? top : lineTop;
                        lineRight = right < lineRight ? right : lineRight;
                        lineBottom = bottom < lineBottom ? bottom : lineBottom;
                    }
                }
                postInvalidate();
                break;
            case MotionEvent.ACTION_POINTER_UP:
            case MotionEvent.ACTION_UP:
                touchTag = NONE;
                break;
        }


        lastX = x;
        lastY = y;
        return true;
    }

    // 高亮选择框左边缘移动
    private void lightLeftMove(float x, float y) {
        if (x < dstRect.left) {
            // 不能超出图片区域
            lineLeft = dstRect.left;
        } else if (lineLeft > lineRight - 50) {
            // 不能靠近选择框右边缘
            lineLeft = lineRight - 50;
        } else {
            lineLeft = (int) x;
        }
    }

    private void lightTopMove(float x, float y) {
        if (y < dstRect.top) {
            lineTop = dstRect.top;
        } else if (lineTop > lineBottom - 50) {
            lineTop = lineBottom - 50;
        } else {
            lineTop = (int) y;
        }
    }

    private void lightRightMove(float x, float y) {
        if (x > dstRect.right) {
            lineRight = dstRect.right;
        } else if (x < lineLeft + 50) {
            lineRight = lineLeft + 50;
        } else {
            lineRight = (int) x;
        }
    }

    private void lightBottomMove(float x, float y) {
        if (y > dstRect.bottom) {
            lineBottom = dstRect.bottom;
        } else if (y < lineTop + 50) {
            lineBottom = lineTop + 50;
        } else {
            lineBottom = (int) y;
        }
    }

    public void setBitmap(Bitmap bitmap) {
        this.bitmap = bitmap;
        bitmapWidth = bitmap.getWidth();
        bitmapHeight = bitmap.getHeight();
        initTag = true;
        postInvalidate();
    }

    public Bitmap getBitmap() {
        Bitmap newBitmap = Bitmap.createBitmap((int) widthSize, (int) heightSize, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(newBitmap);
        draw(canvas);
        canvas.save();
        return Bitmap.createBitmap(newBitmap, lineLeft, lineTop, lineRight - lineLeft, lineBottom - lineTop);
    }
}